﻿using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System8ToyMC;
using Microsoft.Silverlight.Testing;
using System.Windows.Controls.DataVisualization.Charting;
using System.Collections.ObjectModel;
using System.Linq;

namespace t_System8ToyMCControls
{
    /// <summary>
    /// Test out this histogram class!
    /// </summary>
    [TestClass]
    public class t_Histogram : PresentationTest
    {
        Histogram _val;
        Chart _mainChart;
        ColumnSeries _data;

        [TestInitialize]
        public void Setup()
        {
            _val = new Histogram();
            _mainChart = _val.FindName("MainChart") as Chart;

            if (_mainChart.Series != null
                && _mainChart.Series.Count >= 1)
            {
                _data = _mainChart.Series[0] as ColumnSeries;
            }

            TestPanel.Children.Add(_val);
        }

        [TestMethod]
        public void TestCTor()
        {
            Assert.IsNotNull(_val, "Histogram calss wasn't found!");
            Assert.IsNotNull(_mainChart, "Histogram chart can't be found!");
            Assert.IsNotNull(_data, "Main chart series can't be found!");
        }

        [TestMethod]
        [Asynchronous]
        [Timeout(1000)]
        public void TestTitle()
        {
            EnqueueCallback(() => _val.XAxisName = "hi there");
            EnqueueConditional(() => ((string)_mainChart.Title) == "hi there");
            EnqueueTestComplete();
        }

        [TestMethod]
        [Asynchronous]
        public void TestSetSmallDataset()
        {
            double[] data = GenerateDataFlat(100);
            EnqueueCallback(() => _val.HistogramValues = data);
            EnqueueCallback(() => Assert.IsNotNull(_mainChart.DataContext, "The data context seems to be bad!"));
            EnqueueCallback(() => Assert.IsNotNull(_data.ItemsSource, "there doesn't seem to be any items set right now!"));
            EnqueueCallback(() => Assert.IsInstanceOfType(_data.ItemsSource, typeof(Histogram.BinData[]), "ItemsSource isn't expected type"));
            EnqueueCallback(() => Assert.IsTrue((_data.ItemsSource as Histogram.BinData[]).Length > 40, "Count of columns isn't right"));
            EnqueueCallback(() => Assert.IsTrue((_data.ItemsSource as Histogram.BinData[]).Sum(mv => mv.Content) > 90, "Expected at least one thing in this bin!"));
            EnqueueCallback(() => Assert.IsTrue((_data.ItemsSource as Histogram.BinData[]).Sum(mv => mv.Content) <= 100, "Expected at least one thing in this bin!"));
            EnqueueTestComplete();
        }

        [TestMethod]
        [Asynchronous]
        public void TestLargeDataset()
        {
            double[] data = GenerateDataFlat(1000);
            EnqueueCallback(() => _val.HistogramValues = data);
            EnqueueCallback(() => Assert.IsNotNull(_mainChart.DataContext, "The data context seems to be bad!"));
            EnqueueCallback(() => Assert.IsNotNull(_data.ItemsSource, "there doesn't seem to be any items set right now!"));
            EnqueueCallback(() => Assert.IsInstanceOfType(_data.ItemsSource, typeof(Histogram.BinData[]), "ItemsSource isn't expected type"));
            EnqueueCallback(() => Assert.IsTrue((_data.ItemsSource as Histogram.BinData[]).Length > 1.0, "Count of columns isn't right"));
            EnqueueTestComplete();
        }

        [TestMethod]
        [Asynchronous]
        [Timeout(2000)]
        public void TestDisplay()
        {
            EnqueueCallback(() => _val.HistogramValues = GenerateDataFlat(10000));
            EnqueueConditional(() => _data.ItemsSource != null);
            EnqueueConditional(() => (_data.ItemsSource as Histogram.BinData[]).Length > 1.0);
            EnqueueTestComplete();
        }

        [TestMethod]
        [Asynchronous]
        //[Timeout(100)]
        public void TestDisplayTiming()
        {
            EnqueueCallback(() => _val.HistogramValues = GenerateDataFlat(10000));
            EnqueueConditional(() => _data.ItemsSource != null);
            EnqueueConditional(() => (_data.ItemsSource as Histogram.BinData[]).Length > 1.0);
            EnqueueTestComplete();
        }

        [TestMethod]
        [Asynchronous]
        public void TestDisplayTwice()
        {
            EnqueueCallback(() => _val.HistogramValues = GenerateDataFlat(10000));
            Histogram.BinData[] oldData = null;
            EnqueueConditional(() => _data.ItemsSource != null);
            EnqueueCallback(() => oldData = _data.ItemsSource as Histogram.BinData[]);
            EnqueueConditional(() => (_data.ItemsSource as Histogram.BinData[]).Length > 1.0);

            EnqueueCallback(() => _val.HistogramValues = GenerateDataFlat(1000));
            EnqueueConditional(() => oldData != (_data.ItemsSource as Histogram.BinData[]));
            EnqueueCallback(() => oldData = _data.ItemsSource as Histogram.BinData[]);
            EnqueueConditional(() => (_data.ItemsSource as Histogram.BinData[]).Length > 1.0);

            EnqueueTestComplete();
        }

        [TestMethod]
        [Asynchronous]
        [Timeout(2000)]
        public void TestDisplayThreeTimes()
        {
            EnqueueCallback(() => _val.HistogramValues = GenerateDataFlat(10000));
            Histogram.BinData[] oldData = null;
            EnqueueConditional(() => _data.ItemsSource != null);
            EnqueueCallback(() => oldData = _data.ItemsSource as Histogram.BinData[]);
            EnqueueConditional(() => (_data.ItemsSource as Histogram.BinData[]).Length > 1.0);

            EnqueueCallback(() => _val.HistogramValues = GenerateDataFlat(1000));
            EnqueueConditional(() => oldData != (_data.ItemsSource as Histogram.BinData[]));
            EnqueueCallback(() => oldData = _data.ItemsSource as Histogram.BinData[]);
            EnqueueConditional(() => (_data.ItemsSource as Histogram.BinData[]).Length > 1.0);

            EnqueueCallback(() => _val.HistogramValues = GenerateDataFlat(10009));
            EnqueueConditional(() => oldData != (_data.ItemsSource as Histogram.BinData[]));
            EnqueueCallback(() => oldData = _data.ItemsSource as Histogram.BinData[]);
            EnqueueConditional(() => (_data.ItemsSource as Histogram.BinData[]).Length > 1.0);
            EnqueueTestComplete();
        }

        [TestMethod]
        [Asynchronous]
        [Timeout(2000)]
        public void TestDisplayAxisInterval()
        {
            var v = GenerateDataFlat(10000);

            EnqueueCallback(() => _val.HistogramValues = v);
            EnqueueConditional(() => _data.ItemsSource != null);
            EnqueueConditional(() => (_data.ItemsSource as Histogram.BinData[]).Length > 1.0);
            EnqueueCallback(() => Assert.IsTrue(_val.AxisLabelInterval > 900, "interval isn't right (" + _val.AxisLabelInterval + ")"));
            EnqueueTestComplete();
        }

        [TestMethod]
        [Asynchronous]
        [Timeout(2000)]
        public void TestDisplayAxisIntervalSingleValue()
        {
            double[] values = new double[100];
            for (int i = 0; i < 100; i++)
            {
                values[i] = 103.2;
            }
            EnqueueCallback(() => _val.HistogramValues = values);
            EnqueueConditional(() => _data.ItemsSource != null);
            EnqueueConditional(() => (_data.ItemsSource as Histogram.BinData[]).Length > 1.0);
            EnqueueCallback(() => Assert.AreNotEqual(0.0, _val.AxisLabelInterval, "interval isn't right"));
            EnqueueTestComplete();

        }

        [TestMethod]
        [Asynchronous]
        [Timeout(2000)]
        public void TestClone()
        {
            EnqueueCallback(() =>
            {
                _val.HistogramValues = (from i in Enumerable.Range(1, 1000)
                                        select (double)i).ToArray();
                _val.AxisLabelInterval = 100.0;
            });
            EnqueueCallback(() => _val.XAxisName = "fruit");
            EnqueueConditional(() => _data.ItemsSource != null);
            Histogram h = null;
            Chart hChart = null;
            Histogram.BinData[] hData = null;
            Histogram.BinData[] vData = null;

            EnqueueCallback(() => h = _val.CloneHistogram());
            EnqueueCallback(() => TestPanel.Children.Add(h));
            EnqueueCallback(() =>
            {
                hChart = h.FindName("MainChart") as Chart;
            });
            EnqueueConditional(() => (hChart.Series[0] as ColumnSeries).ItemsSource != null);
            EnqueueCallback(() =>
                {
                    hData = (hChart.Series[0] as ColumnSeries).ItemsSource as Histogram.BinData[];
                    vData = (_data.ItemsSource) as Histogram.BinData[];
                    Assert.AreEqual("fruit", h.XAxisName, "Title was not cloned correctly");
                    Assert.AreEqual(vData.Length, hData.Length, "The # of bins isn't the same");
                    for (int i = 0; i < vData.Length; i++)
                    {
                        Assert.AreEqual(vData[i].BinValue, hData[i].BinValue, "Bin value for " + i.ToString() + " is not correct");
                        Assert.AreEqual(vData[i].Content, hData[i].Content, "Context value for bin " + i.ToString() + "is not correct");
                    }
                    Assert.AreEqual(_val.AxisLabelInterval, h.AxisLabelInterval, "The axis label intervals are not matching!");
                });

            EnqueueTestComplete();
        }

        [TestMethod]
        [Asynchronous]
        [Timeout(2000)]
        public void TestCloneEmptyHisto()
        {
            EnqueueCallback(() => _val.XAxisName = "fruit");
            Histogram h = null;
            Chart hChart = null;
            Histogram.BinData[] hData = null;

            EnqueueCallback(() => h = _val.CloneHistogram());
            EnqueueCallback(() => TestPanel.Children.Add(h));
            EnqueueDelay(50);
            EnqueueCallback(() => Assert.AreEqual("fruit", h.XAxisName, "Title was not cloned correctly"));
            EnqueueCallback(() =>
            {
                hChart = h.FindName("MainChart") as Chart;
                hData = (hChart.Series[0] as ColumnSeries).ItemsSource as Histogram.BinData[];
                Assert.IsNull(hData, "Expected the cloned histo to also have a null data series!");
            });
            EnqueueTestComplete();
        }

        private static double[] GenerateDataFlat(int dsize)
        {
            double[] data = new double[dsize];
            Random r = new Random();
            for (int i = 0; i < dsize; i++)
            {
                data[i] = r.NextDouble() * dsize;
            }
            return data;
        }
    }
}